/*
* Copyright (c) 2011 adVolition
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* Except as contained in this notice, the name(s) of the above
* copyright holders shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
 */

package NeuralNetwork;
import com.thoughtworks.xstream.annotations.*;

/**
 * This is a class of objects that hold a cumulative value controlled by adjoining edges.
 */
@XStreamAlias("node") public class Node {
    @XStreamAlias("value") @XStreamAsAttribute private Double _initialValue;

    protected transient Bundle _parentBundle;
    protected transient Mutability _parentFidelity;

    private transient Double _currentValue = 0.0;
    private transient Double _futureValue = 0.0;

    public Node(Bundle parentBundle) {
        _parentBundle = parentBundle;
        configureObject();
    }

    public Node(Double value, Bundle parentBundle) {
        _parentBundle = parentBundle;
        _initialValue = value;
        configureObject();
    }

    public Object readResolve() {
        configureObject();
        return this;
    }

    /** Used by class constructor and readResolve routines to ensure that newly created
     * objects are configured properly.
     * @return 
     **/    
    private void configureObject() {
        if (_parentBundle == null) _parentBundle = new Bundle();
        if (_parentFidelity == null) _parentFidelity = new Mutability();
        if (_initialValue == null) _initialValue = 0.0;
        _currentValue = _initialValue;
        _futureValue = _initialValue;      
    }
    
    public void reset() {
        _currentValue = _initialValue;
        _futureValue = _initialValue;
    }

    /**
     * Adds the indicated value to the future value of the node.  However, the future
     * value only becomes the current value after the advanceTime function is called.
     * @param value
     */
    public void addToNode(int value) {
        _futureValue += value;
    }

    /**
     * Assigns a parent to each of the child and its children.
     * @param parent
     */
    public void assignParent(Bundle parent) {
        _parentBundle = parent;
        _parentFidelity = parent.getFidelity();
    }
    
    
    public void computeFutureState(Double timeIncrement) {

    }

    public void implementFutureState() {
        _currentValue = _futureValue;
    }

    /**
     * Sets the current value of the node to the future value of the node.
     */
    public void advanceTime() {
        _currentValue = _futureValue;
    }

    /**
     * This is an error-prone method for cloning the object.  It is used to generate mutant robot offspring.
     * @param parentBundle 
     * @return
     */
    public Node getClone(Bundle parentBundle) {
        return new Node(cloneValue(), parentBundle);
    }

    private Double cloneValue() {
        if (Math.random() < _parentFidelity.getMutateNode()) {
            return Math.random();
        }

        return _initialValue;
    }
    
    /**
     * Returns the value of the node.
     * @return
     */
    public Double getValue() {
        return _currentValue;
    }

    /**
     * Sets the value of the node.
     * @param value
     */
    public void setValue(Double value) {
        _currentValue = value;
    }

    /**
     * Ensures that the specified value is not less than 0 or greater than 100.
     * @param value
     * @return
     */
    private Double boundValue(Double value) {
        if (value < 0.0) return 0.0;
        if (value > 100.0) return 100.0;
        return value;
    }
}
